﻿using System;
using System.IO;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using System.Xml;
using Centido.Core.Dto;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Centido.Core.Test
{
    /// <summary>
    ///   Testing the data transfer object for a table row.
    /// </summary>
    [TestClass]
    public class TableRowDataDtoTest : GenericDtoTest
    {
        /// <summary>
        ///   Retrieves the name of the data transfer object xml tag.
        /// </summary>
        /// <returns></returns>
        protected override string GetXmlTag()
        {
            return TableRowDataDto.XmlTag;
        }


        /// <summary>
        ///   Retrives the current xml schema version.
        /// </summary>
        /// <returns></returns>
        protected override string GetCurrentXmlSchemaVersion()
        {
            return TableRowDataDto.CurrentXmlSchemaVersion;
        }


        /// <summary>
        ///   Creates a new data transfer object.
        /// </summary>
        /// <returns></returns>
        protected override DataTransferObject CreateDto()
        {
            var dto =  new TableRowDataDto
            {
                Id = Guid.NewGuid(),
                CreatedBy = "user_1",
                CreatedOn = DateTime.Now.AddDays(-6),
                UpdatedBy = "user_2",
                UpdatedOn = DateTime.Now.AddDays(-4),
                Owner = "user_3",
                Version = Guid.NewGuid(),
                DeletedBy = "user_3",
                DeletedOn = DateTime.Now.AddDays(-1)
            };

            dto.AddColumnValue("my_col", "column value");
            dto.AddColumnValue("my_col2", "1");

            return dto;
        }


        /// <summary>
        ///   Retrieves the list of data transfer object fields.
        /// </summary>
        /// <returns></returns>
        protected override IEnumerable<DtoFieldInfo> GetFields()
        {
            yield return new DtoFieldInfo
            {
                Name = "Id",
                XmlName = TableRowDataDto.IdAttribute,
                IsRequired = true,
                FieldType = DtoFieldType.Guid,
                SampleValue = Guid.NewGuid()
            };

            yield return new DtoFieldInfo
            {
                Name = "Owner",
                XmlName = TableRowDataDto.OwnerAttribute,
                IsRequired = false,
                FieldType = DtoFieldType.String,
                SampleValue = "owner"
            };

            yield return new DtoFieldInfo
            {
                Name = "Version",
                XmlName = TableRowDataDto.VersionAttribute,
                IsRequired = false,
                FieldType = DtoFieldType.Guid,
                SampleValue = Guid.NewGuid()
            };

            yield return new DtoFieldInfo
            {
                Name = "CreatedBy",
                XmlName = TableRowDataDto.CreatedByAttribute,
                IsRequired = false,
                FieldType = DtoFieldType.String,
                SampleValue = "created_by"
            };

            yield return new DtoFieldInfo
            {
                Name = "UpdatedBy",
                XmlName = TableRowDataDto.UpdatedByAttribute,
                IsRequired = false,
                FieldType = DtoFieldType.String,
                SampleValue = "updated_by"
            };

            yield return new DtoFieldInfo
            {
                Name = "DeletedBy",
                XmlName = TableRowDataDto.DeletedByAttribute,
                IsRequired = false,
                FieldType = DtoFieldType.String,
                SampleValue = "deleted_by"
            };

            yield return new DtoFieldInfo
            {
                Name = "CreatedOn",
                XmlName = TableRowDataDto.CreatedOnAttribute,
                IsRequired = false,
                FieldType = DtoFieldType.DateTime,
                SampleValue = DateTime.Now.AddDays(-6)
            };

            yield return new DtoFieldInfo
            {
                Name = "UpdatedOn",
                XmlName = TableRowDataDto.UpdatedOnAttribute,
                IsRequired = false,
                FieldType = DtoFieldType.DateTime,
                SampleValue = DateTime.Now.AddDays(-4)
            };

            yield return new DtoFieldInfo
            {
                Name = "DeletedOn",
                XmlName = TableRowDataDto.DeletedOnAttribute,
                IsRequired = false,
                FieldType = DtoFieldType.DateTime,
                SampleValue = DateTime.Now.AddDays(-2)
            };
        }


        /// <summary>
        ///   Copies the properties of the data transfer object to the corresponding object.
        /// </summary>
        /// <param name="dto">The data transfer object.</param>
        /// <returns>Returns the corresponding object after copying.</returns>
        protected override object CopyFrom(DataTransferObject dto)
        {
            return null;
        }


        /// <summary>
        ///   Creates a data transfer object from the correpsonding object.
        /// </summary>
        /// <param name="dto">The created data transfer object.</param>
        /// <param name="initialObject">The initial object.</param>
        protected override void CreateDtoFromObject(out DataTransferObject dto, out object initialObject)
        {
            dto = null;
            initialObject = null;
        }


        /// <summary>
        ///   Reading the column values list from xml.
        /// </summary>
        [TestMethod]
        public void ReadingColumnListFromXml()
        {
            // Creating a data row
            var xml = string.Format("<{0} {1}=\"{2}\">",
                TableRowDataDto.XmlTag,
                TableRowDataDto.IdAttribute,
                Guid.NewGuid());

            // Creating a column list
            xml += string.Format("<{0} {1}=\"{2}\">{3}</{4}><{5} {6}=\"{7}\">{8}</{9}></{10}>",
                TableRowDataDto.ColumnValueTag,
                TableRowDataDto.ColumnNameAttribute,
                "col_a",
                "value_a",
                TableRowDataDto.ColumnValueTag,
                TableRowDataDto.ColumnValueTag,
                TableRowDataDto.ColumnNameAttribute,
                "col_b",
                "value_b",
                TableRowDataDto.ColumnValueTag,
                TableRowDataDto.XmlTag);

            var stream = new XmlTextReader(new MemoryStream(Encoding.UTF8.GetBytes(xml)));

            var rowDataDto = new TableRowDataDto();

            rowDataDto.ReadXml(stream);

            Assert.AreEqual(rowDataDto.ColumnValues.Count(), 2);
            Assert.AreEqual(rowDataDto.ColumnValues.Count(v => v.Key == "col_a" && v.Value == "value_a"), 1);
            Assert.AreEqual(rowDataDto.ColumnValues.Count(v => v.Key == "col_b" && v.Value == "value_b"), 1);
        }


        /// <summary>
        ///   Reading empty and null column values.
        /// </summary>
        [TestMethod]
        public void ReadingEmptyAndNullColumnValues()
        {
            // Creating a data row
            var xml = string.Format("<{0} {1}=\"{2}\">",
                TableRowDataDto.XmlTag,
                TableRowDataDto.IdAttribute,
                Guid.NewGuid());

            // Creating an empty column list
            xml += string.Format("<{0} {1}=\"{2}\" /><{3} {4}=\"{5}\"></{6}></{7}>",
                TableRowDataDto.ColumnValueTag,
                TableRowDataDto.ColumnNameAttribute,
                "col_a",
                TableRowDataDto.ColumnValueTag,
                TableRowDataDto.ColumnNameAttribute,
                "col_b",
                TableRowDataDto.ColumnValueTag,
                TableRowDataDto.XmlTag);

            var stream = new XmlTextReader(new MemoryStream(Encoding.UTF8.GetBytes(xml)));

            var rowDataDto = new TableRowDataDto();

            rowDataDto.ReadXml(stream);

            Assert.AreEqual(rowDataDto.ColumnValues.Count(), 2);
            Assert.AreEqual(rowDataDto.ColumnValues.Count(v => v.Key == "col_a" && v.Value == null), 1);
            Assert.AreEqual(rowDataDto.ColumnValues.Count(v => v.Key == "col_b" && v.Value == string.Empty), 1);
        }


        /// <summary>
        ///   Writing and reading the column value list.
        /// </summary>
        [TestMethod]
        public void WritingAndReadingColumnList()
        {
            var dataRowDto = new TableRowDataDto
            {
                Id = Guid.NewGuid()
            };

            dataRowDto.AddColumnValue("col_a", "value_a");
            dataRowDto.AddColumnValue("col_b", "value_b");
            dataRowDto.AddColumnValue("col_c", string.Empty);
            dataRowDto.AddColumnValue("col_d", null);

            var memoryStream = new MemoryStream();
            var writer = new XmlTextWriter(memoryStream, Encoding.UTF8);

            dataRowDto.WriteXml(writer);

            writer.Flush();

            memoryStream.Position = 0;
            var streamReader = new StreamReader(memoryStream);
            var xml = streamReader.ReadToEnd();

            Assert.IsFalse(string.IsNullOrEmpty(xml));

            memoryStream.Position = 0;
            var reader = new XmlTextReader(memoryStream);

            var dto = new TableRowDataDto();

            dto.ReadXml(reader);

            Assert.AreEqual(dto.ColumnValues.Count(), 4);
            Assert.AreEqual(dto.ColumnValues.Count(v => v.Key == "col_a" && v.Value == "value_a"), 1);
            Assert.AreEqual(dto.ColumnValues.Count(v => v.Key == "col_b" && v.Value == "value_b"), 1);
            Assert.AreEqual(dto.ColumnValues.Count(v => v.Key == "col_c" && v.Value == string.Empty), 1);
            Assert.AreEqual(dto.ColumnValues.Count(v => v.Key == "col_d" && v.Value == null), 1);
        }
    }
}
